package com.tsd.shiro.config;

import com.tsd.core.shiro.config.ShiroModularRealmAuthenticator;
import com.tsd.core.shiro.config.ShiroWebSessionManager;
import com.tsd.shiro.realm.SysUserRealm;
import com.tsd.shiro.realm.TokenRealm;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.MethodInvokingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

/**
 * @ClassName: BaseShiroConfig
 * @Description: Shiro相关配置
 * @Author: Hillpool
 * @Date: 2022/7/15 9:46
 * @Version: 1.0
 */
@Configuration
public class BaseShiroConfig {

    /**
     * 静态注入
     *
     * @return
     */
    @Bean
    public MethodInvokingBean shiroAuthorizationInfoHelper() {
        MethodInvokingBean bean = new MethodInvokingBean();
        bean.setStaticMethod("com.tsd.core.shiro.helper.ShiroAuthorizationInfoHelper.setEhCacheManager");
        bean.setArguments(ehCacheManager());
        return bean;
    }

    /**
     * Token认证-授权
     *
     * @return
     */
    @Bean
    public Realm tokenRealm() {
        TokenRealm realm = new TokenRealm();
        realm.setCredentialsMatcher(new ShiroCredentialsMatcher());
        return realm;
    }

    /**
     * 普通登录认证-授权
     *
     * @return
     */
    @Bean
    public Realm sysUserRealm() {
        SysUserRealm realm = new SysUserRealm();
        realm.setCredentialsMatcher(new ShiroCredentialsMatcher());
        return realm;
    }

    /**
     * 生命周期处理器
     *
     * @return
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 开启注解模式
     *
     * @return
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

    /**
     * 用户授权信息Cache, 采用EhCache
     *
     * @return
     */
    @Bean(name = "ehCacheManager")
    public EhCacheManager ehCacheManager() {
        EhCacheManager manager = new EhCacheManager();
        manager.setCacheManagerConfigFile("classpath:ehcache.xml");
        return manager;
    }

    /**
     * Realm管理，主要针对多realm 授权
     */
    @Bean
    public ModularRealmAuthenticator modularRealmAuthenticator() {
        //自己重写的ModularRealmAuthenticator
        ShiroModularRealmAuthenticator modularRealmAuthenticator = new ShiroModularRealmAuthenticator();
        modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        return modularRealmAuthenticator;
    }

    @Bean(value = "sessionManager")
    public SessionManager sessionManager() {
        ShiroWebSessionManager manager = new ShiroWebSessionManager();
        // 去掉shiro登录时url里的JSESSIONID
        manager.setSessionIdUrlRewritingEnabled(false);
        // 关闭session校验轮询
        manager.setSessionValidationSchedulerEnabled(false);
        manager.setGlobalSessionTimeout(30 * 60 * 1000);
        return manager;
    }

    /**
     * 开启Shiro-aop注解支持
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    public DefaultShiroFilterChainDefinition getBaseAuthFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
        chainDefinition.addPathDefinition("/auth/401", "anon");
        chainDefinition.addPathDefinition("/auth/index", "anon");
        chainDefinition.addPathDefinition("/auth/403", "anon");
        chainDefinition.addPathDefinition("/auth/404", "anon");
        chainDefinition.addPathDefinition("/admin/auth/login", "anon");
        chainDefinition.addPathDefinition("/admin/auth/captchaImage", "anon");
        chainDefinition.addPathDefinition("/admin/auth/401", "anon");
        chainDefinition.addPathDefinition("/admin/auth/index", "anon");
        chainDefinition.addPathDefinition("/admin/auth/403", "anon");

        chainDefinition.addPathDefinition("/api/v2/getVerifyCode.action", "anon");
        chainDefinition.addPathDefinition("/api/v2/login.action", "anon");
        chainDefinition.addPathDefinition("/api/v2/loginApp.action", "anon");
        chainDefinition.addPathDefinition("/api/v2/loginGuest.action", "anon");
        chainDefinition.addPathDefinition("/api/v2/syncUserInfo.action", "anon");
        chainDefinition.addPathDefinition("/api/v2/applyChangeDevice.action", "anon");
        chainDefinition.addPathDefinition("/api/v2/getQueryValue4ViewAttachBySid.action", "anon");
        chainDefinition.addPathDefinition("/druid/**", "anon");
        chainDefinition.addPathDefinition("/static/**", "anon");
        chainDefinition.addPathDefinition("/file/**", "anon");
        chainDefinition.addPathDefinition("/wx/**", "anon");
        chainDefinition.addPathDefinition("/anon/**", "anon");
        chainDefinition.addPathDefinition("/short/**", "anon");
        return chainDefinition;
    }
}
